package cn.com.pc.content.util;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Bean属性工具类扩展
 *
 * @author hjlu
 * @create 2021/3/19 上午11:18
 */
public class BeanUtils extends org.springframework.beans.BeanUtils {
    public static String[] getNullPropertyNames ( Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

        Set< String> emptyNames = new HashSet< String>();
        for(java.beans.PropertyDescriptor pd : pds) {
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) emptyNames.add(pd.getName());
        }
        String[] result = new String[emptyNames.size()];
        return emptyNames.toArray(result);
    }

    public static void copyPropertiesIgnoreNull( Object src, Object target){
        BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
    }


    /**
     * 判断是否类中的属性
     * @param clazz
     * @param property
     * @return
     */
    public static boolean isClassProperty(Class<?> clazz, String property) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (property.equals(field.getName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 比较两个对象，返回不相等的属性列表
     * @param source
     * @param dest
     * @return
     */
    public static List<String> comparePropertyIgnore(Object source, Object dest, String ...ignoreProperties) throws Exception {
        Object realSrc;
        if (source.getClass() != dest.getClass()) {
            realSrc = dest.getClass().getDeclaredConstructor().newInstance();
            copyProperties(source, realSrc);
        } else {
            realSrc = source;
        }
        final BeanWrapper src = new BeanWrapperImpl(realSrc);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
        final BeanWrapper dst = new BeanWrapperImpl(dest);

        ArrayList<String> diff = new ArrayList<>();
        for(java.beans.PropertyDescriptor pd : pds) {
            if (ArrayUtils.contains(ignoreProperties, pd.getName())) {
                continue;
            }
            Object srcValue = src.getPropertyValue(pd.getName());
            Object dstValue = dst.getPropertyValue(pd.getName());
            if (dstValue == null) {continue;}
            String srcStr = JsonUtils.obj2String(srcValue);
            String dstStr = JsonUtils.obj2String(dstValue);
            if (StringUtils.compare(srcStr, dstStr) != 0) {
                diff.add(pd.getName() + ":" + srcStr + "->" + dstStr);
            }
        }
        return diff;
    }

    /**
     * 比较两个对象，返回不相等的属性列表
     * @param source
     * @param dest
     * @return
     */
    public static List<String> comparePropertyWith(Object source, Object dest, String ...withProperties) throws Exception {
        Object realSrc;
        if (source.getClass() != dest.getClass()) {
            realSrc = dest.getClass().getDeclaredConstructor().newInstance();
            copyProperties(source, realSrc);
        } else {
            realSrc = source;
        }
        final BeanWrapper src = new BeanWrapperImpl(realSrc);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
        final BeanWrapper dst = new BeanWrapperImpl(dest);

        ArrayList<String> diff = new ArrayList<>();
        for(java.beans.PropertyDescriptor pd : pds) {
            if (ArrayUtils.contains(withProperties, pd.getName())) {
                Object srcValue = src.getPropertyValue(pd.getName());
                Object dstValue = dst.getPropertyValue(pd.getName());
                if (dstValue == null) {continue;}
                String srcStr = JsonUtils.obj2String(srcValue);
                String dstStr = JsonUtils.obj2String(dstValue);
                if (StringUtils.compare(srcStr, dstStr) != 0) {
                    diff.add(pd.getName() + ":" + srcStr + "->" + dstStr);
                }
            }
        }
        return diff;
    }
}

